﻿using System;
using System.Text;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;
using WebuSocketCore;


/// <summary>
/// Version 4.2
/// * WSC为单纯的WebSocket客户端，修改于WS 4.1.1
/// Version 4.1.1
/// * 修改了WS_Heart
/// * 修改了if_用于外部设定，is_用于内部状态
/// Version 4.1
/// </summary>
public class WSC : MonoBehaviour
{
	[Header("基本连接")]
	public string url;

	[Header("断网重连")]
	public bool if_reconnect = true;
	public float reconnect_time = 3;
	public bool if_reconnect_print = false;

	[Header("心跳包")]
	public bool if_heart = true;
	public float heart_time = 60;
	public string heart_send_iot = "t";
	public string heart_recv_iot = "t";
	public bool if_heart_print = false;

	[Header("回调函数")]
	//连接回调
	public UnityEvent OnConnect;
	private bool is_connect_callback = false;
	//发送回调
	public bool if_send_callback = false;
	public SendEvent OnSend;
	[Serializable]
	public class SendEvent : UnityEvent<string>{}
	//接收回调
	public RecvEvent OnRecv;
	[Serializable]
	public class RecvEvent : UnityEvent<string> { }
	//关闭回调
	public UnityEvent OnClose;
	private bool is_close_callback = false;

	private WebuSocket webSocket;
	//判断是否处于关闭状态(未创建前状态)
	private bool is_create = false;
	private bool is_connect = false;
	//心跳包是否已经连接
	private bool is_heart_link = true;
	//是否收到
	private bool is_recv = false;
	private string recv;

	private void Update()
	{
		if (is_create) {
			if (is_recv)
			{
				is_recv = false;
				StartCoroutine(Recv(recv));
			}

			if (is_connect_callback)
			{
				is_connect_callback = false;
				if (OnConnect.GetPersistentEventCount() > 0)
				{
					OnConnect.Invoke();
				}
			}

			if (is_close_callback)
			{
				is_close_callback = false;
				if (OnClose.GetPersistentEventCount() > 0)
				{
					OnClose.Invoke();
				}
			}
		}
	}

	/// <summary>
	/// /创建websocket
	/// </summary>
	public void Create()
	{
		print("WS:" + url);

		if (if_heart) {
			heart_recv_iot = FormatIot(heart_recv_iot);
			if (!IsInvoking("WS_Heart"))
				this.InvokeRepeating("WS_Heart", 30f, heart_time);
		}
		if (if_reconnect) {
			if (!IsInvoking("WS_ReConnect"))
				this.InvokeRepeating("WS_ReConnect", 5f, reconnect_time);
		}

		//默认设置，防止启动时旧状态
		is_connect_callback = false;
		is_close_callback = false;

		webSocket = new WebuSocket(
			// url.
			url,

			// buffer size.
			1024,

			// handler for connection established to server.
			() =>
			{
				//Debug.Log("connected to websocket echo-server. send hello to echo-server");
				is_connect = true;
				is_connect_callback = true;
				print("wsc连接成功");
			},

			// handler for receiving data from server. 
			datas =>
			{
				/*
					this handler is called from system thread. not Unity's main thread.
					and, datas is ArraySegment<byte> x N. 
					SHOULD COPY byte data from datas HERE.
					do not copy ArraySegment<byte> itself.
					these data array will be destroyed soon after leaving this block.
				*/
				while (0 < datas.Count)
				{
					ArraySegment<byte> data = datas.Dequeue();

					byte[] bytes = new byte[data.Count];
					Buffer.BlockCopy(data.Array, data.Offset, bytes, 0, data.Count);

					string message = Encoding.UTF8.GetString(bytes);
					string msg = FormatIot(message);
					//心跳包判断 若{}格式，注意收到单引号与空格
					if (msg.Equals(heart_recv_iot))
					{
						is_heart_link = true;
						if (if_heart_print) {
							print("心跳包回馈：" + message);
						}
					}
					else
					{
						is_recv = true;
						recv = msg;
					}

				}
			},
			() =>
			{
				Debug.Log("received server ping. automatically ponged.");
			},
			closeReason =>
			{
				//Debug.Log("closed, closeReason:" + closeReason);
				is_connect = false;
				if (is_create)
				{
					is_close_callback = true;
				}
			},
			(errorEnum, exception) =>
			{
				//Debug.LogError("error, errorEnum:" + errorEnum + " exception:" + exception);
				is_connect = false;
				if (is_create)
				{
					is_close_callback = true;
				}
			},
			new Dictionary<string, string>
			{
				// set WebSocket connection header parameters here!
			}
		);
		is_create = true;
	}

	/// <summary>
	/// 心跳包循环函数
	/// </summary>
	private void WS_Heart()
	{
		if (if_heart && is_connect)
		{
			if (!is_heart_link)
			{
				is_heart_link = true;
				if (if_heart_print)
				{
					print("未收到心跳包：" + heart_send_iot);
				}
				if (if_reconnect) {
					is_connect = false;
				}
			}
			if (if_heart_print) {
				print("发送心跳包:" + heart_send_iot);
			}
			webSocket.SendString(heart_send_iot);
			is_heart_link = false;

		}
	}

	/// <summary>
	/// 重新设置心跳包
	/// </summary>
	public void SetHeart(float delay = 0)
	{
		//清理
		if (IsInvoking("WS_Heart"))
		{
			CancelInvoke("WS_Heart");
		}

		if (if_heart)
		{
			if (heart_send_iot != String.Empty && heart_recv_iot != String.Empty && heart_time>0) {
				this.InvokeRepeating("WS_Heart", delay, heart_time);
			}
		}

		print("SetHeart");
	}

	/// <summary>
	/// 断网重连
	/// </summary>
	private void WS_ReConnect()
	{
		if (if_reconnect && !is_connect)
		{
			if (if_reconnect_print) {
				print("断网重连");
			}

			webSocket = WebuSocket.Reconnect(webSocket);

		}
	}

	/// <summary>
	/// 重新设置断网重连
	/// </summary>
	public void SetReConnect(float delay = 0)
	{
		//清理
		if (IsInvoking("WS_ReConnect"))
		{
			CancelInvoke("WS_ReConnect");
		}

		if (if_reconnect)
		{
			if (reconnect_time>0) {
				this.InvokeRepeating("WS_ReConnect", delay, reconnect_time);
			}
		}

		print("SetReConnect");
	}

	/// <summary>
	/// 发送
	/// </summary>
	public void Send(string msg)
	{
		if (is_connect) {
			msg = FormatIot(msg);
			webSocket.SendString(msg);
			if (if_send_callback && OnSend.GetPersistentEventCount() > 0)
			{
				try
				{
					OnSend.Invoke(msg);
				}
				catch (Exception e)
				{
					print("WSC , Send运行错误:" + msg);
					print(e);
				}
			}
		}
	}

	/// <summary>
	/// 收到信息
	/// </summary>
	public IEnumerator Recv(string recv)
	{
		try
		{
			string json_str = recv.Replace('\'', '"');
			if (OnRecv.GetPersistentEventCount() > 0)
			{
				OnRecv.Invoke(json_str);
			}
		}
		catch (Exception e)
		{
			print("WSC , Recv运行错误:" + recv);
			print(e);
		}
		
		yield return true;
	}

	/// <summary>
	/// Iot格式化
	/// </summary>
	/// <returns></returns>
	public string FormatIot(string iot)
	{
		iot = iot.Replace('"', '\'');
		return iot.Replace(" ", "");
	}

	/// <summary>
	/// 关闭连接
	/// </summary>
	public void Close()
	{
		if (is_connect)
		{
			webSocket.Disconnect();
		}
	}

	/// <summary>
	/// 退出
	/// </summary>
	void OnApplicationQuit()
	{
		try
		{
			CancelInvoke("WS_Heart");
			CancelInvoke("WS_ReConnect");
			webSocket.Disconnect();
		}
		catch (Exception e)
		{
			print(e);
		}
	}
}
